package cn.iocoder.yudao.module.infra.service.infotablecollect;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.infocolumncollect.vo.InfoColumnCollectBaseVO;
import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.infocolumncollect.InfoColumnCollectDO;
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
import cn.iocoder.yudao.module.infra.dal.mysql.infocolumncollect.InfoColumnCollectMapper;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import cn.iocoder.yudao.module.infra.controller.admin.infotablecollect.vo.*;
import cn.iocoder.yudao.module.infra.dal.dataobject.infotablecollect.InfoTableCollectDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import cn.iocoder.yudao.module.infra.convert.infotablecollect.InfoTableCollectConvert;
import cn.iocoder.yudao.module.infra.dal.mysql.infotablecollect.InfoTableCollectMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;

/**
 * 基础资料表汇总 Service 实现类
 *
 * @author lry
 */
@Service
@Validated
public class InfoTableCollectServiceImpl implements InfoTableCollectService {

    @Resource
    private DatabaseTableService databaseTableService;

    @Resource
    private InfoTableCollectMapper infoTableCollectMapper;

    @Resource
    private InfoColumnCollectMapper columnCollectMapper;

    @Resource
    private CodegenTableMapper codegenTableMapper;
    @Resource
    private CodegenColumnMapper codegenColumnMapper;

    @Resource
    private AdminUserApi userApi;

    @Resource
    private CodegenBuilder codegenBuilder;
    @Resource
    private CodegenEngine codegenEngine;

    @Resource
    private CodegenProperties codegenProperties;

    @Override
    public Long createInfoTableCollect(InfoTableCollectCreateReqVO createReqVO) {
        // 插入
        InfoTableCollectDO infoTableCollect = InfoTableCollectConvert.INSTANCE.convert(createReqVO);
        infoTableCollectMapper.insert(infoTableCollect);
        // 返回
        return infoTableCollect.getId();
    }

    @Override
    public void updateInfoTableCollect(InfoTableCollectUpdateReqVO updateReqVO) {
        // 校验存在
        validateInfoTableCollectExists(updateReqVO.getId());
        // 更新
        InfoTableCollectDO updateObj = InfoTableCollectConvert.INSTANCE.convert(updateReqVO);
        infoTableCollectMapper.updateById(updateObj);
    }

    @Override
    public void deleteInfoTableCollect(Long id) {
        // 校验存在
        validateInfoTableCollectExists(id);
        // 删除
        infoTableCollectMapper.deleteById(id);
    }

    private void validateInfoTableCollectExists(Long id) {
        if (infoTableCollectMapper.selectById(id) == null) {
            throw exception(INFO_TABLE_COLLECT_NOT_EXISTS);
        }
    }

    @Override
    public InfoTableCollectDO getInfoTableCollect(Long id) {
        return infoTableCollectMapper.selectById(id);
    }

    @Override
    public List<InfoTableCollectDO> getInfoTableCollectList(Collection<Long> ids) {
        return infoTableCollectMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<InfoTableCollectDO> getInfoTableCollectPage(InfoTableCollectPageReqVO pageReqVO) {
        return infoTableCollectMapper.selectPage(pageReqVO);
    }

    @Override
    public List<InfoTableCollectDO> getInfoTableCollectList(InfoTableCollectExportReqVO exportReqVO) {
        return infoTableCollectMapper.selectList(exportReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> createCodegenList(Long userId, CodegenCreateListReqVO reqVO) {
        List<Long> ids = new ArrayList<>(reqVO.getTableNames().size());
        // 遍历添加。虽然效率会低一点，但是没必要做成完全批量，因为不会这么大量
        reqVO.getTableNames().forEach(tableName -> ids.add(createCodegen(userId, reqVO.getDataSourceConfigId(), tableName)));
        return ids;
    }

    @Override
    public void deleteCodegen(Long tableId) {
        // 校验是否已经存在
        if (infoTableCollectMapper.selectById(tableId) == null) {
            throw exception(CODEGEN_TABLE_NOT_EXISTS);
        }

        // 删除 table 表定义
        infoTableCollectMapper.deleteById(tableId);
        // 删除 column 字段定义
        columnCollectMapper.deleteListByTableId(tableId);
    }

    @Override
    public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) {
        List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment);
        // 移除已经生成的表
        // 移除在 Codegen 中，已经存在的
        Set<String> existsTables = CollectionUtils.convertSet(
                infoTableCollectMapper.selectListByDataSourceConfigId(dataSourceConfigId), InfoTableCollectDO::getTableName);
        tables.removeIf(table -> existsTables.contains(table.getName()));
        return CodegenConvert.INSTANCE.convertList04(tables);
    }

    @Override
    public List<InfoColumnCollectDO> getInfoColumnCollectListByTableId(Long tableId) {
        return columnCollectMapper.getInfoColumnCollectListByTableId(tableId);
    }

    @Override
    public InfoTableCollectDO getByTableName(String tableName) {
        return infoTableCollectMapper.selectByTableName(tableName);
    }


    public Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) {
        // 从数据库中，获得数据库表结构
        TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName);
        // 导入
        return createCodegen0(userId, dataSourceConfigId, tableInfo);
    }

    private void validateTableInfo(TableInfo tableInfo) {
        if (tableInfo == null) {
            throw exception(CODEGEN_IMPORT_TABLE_NULL);
        }
        if (StrUtil.isEmpty(tableInfo.getComment())) {
            throw exception(CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL);
        }
        if (CollUtil.isEmpty(tableInfo.getFields())) {
            throw exception(CODEGEN_IMPORT_COLUMNS_NULL);
        }
        tableInfo.getFields().forEach(field -> {
            if (StrUtil.isEmpty(field.getComment())) {
                throw exception(CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName());
            }
        });
    }

    private Long createCodegen0(Long userId, Long dataSourceConfigId, TableInfo tableInfo) {
        // 校验导入的表和字段非空
        validateTableInfo(tableInfo);
        // 校验是否已经存在
        if (infoTableCollectMapper.selectByTableNameAndDataSourceConfigId(tableInfo.getName(),
                dataSourceConfigId) != null) {
            throw exception(CODEGEN_TABLE_EXISTS);
        }

        // 构建 CodegenTableDO 对象，插入到 DB 中
        InfoTableCollectDO table = codegenBuilder.buildTableCollect(tableInfo);
        table.setDataSourceConfigId(dataSourceConfigId);
        table.setScene(CodegenSceneEnum.ADMIN.getScene()); // 默认配置下，使用管理后台的模板
        table.setFrontType(codegenProperties.getFrontType());
        table.setAuthor(userApi.getUser(userId).getNickname());
        infoTableCollectMapper.insert(table);

        // 构建 CodegenColumnDO 数组，插入到 DB 中
        List<InfoColumnCollectDO> columns = codegenBuilder.buildColumnCollects(table.getId(), tableInfo.getFields());
        // 如果没有主键，则使用第一个字段作为主键
        if (!tableInfo.isHavePrimaryKey()) {
            columns.get(0).setPrimaryKey(true);
        }
        columnCollectMapper.insertBatch(columns);
        return table.getId();
    }



}
